9장. 추론 최적화
출처 — Chip Huyen, 『AI 엔지니어링』(한국어판), 9장 (pp. 472~518). 원문 PDF
ai_engineering_final_v11_260909.pdf(2026-09-09 판)모델을 더 좋게 만드는 법은 앞선 장들이 다뤘다. 이 장은 그 모델을 더 빠르고 더 저렴하게 서빙하는 법을 다룬다 — 병목을 진단하는 지표, 가속기의 특성, 모델 자체를 깎는 기법, 서비스 단에서 자원을 배분하는 기법까지 순서대로 짚는다.
학습 목표
이 장을 끝내면 다음을 할 수 있다.
- 연산 제약과 메모리 대역폭 제약을 구분하고, 프리필과 디코딩이 각각 어느 쪽 병목에 해당하는지 설명한다.
- TTFT·TPOT·처리량·굿풋·MFU·MBU 지표를 정의하고, 각 지표가 무엇을 놓치는지(평균의 함정, 활용률의 함정)를 근거로 설명한다.
- 가속기의 핵심 사양(연산 성능·메모리 대역폭·전력 소모)을 읽고, 작업 특성에 맞춰 가속기를 고르는 세 가지 질문을 적용한다.
- 모델 압축·추측 디코딩·어텐션 최적화 기법을 구분하고, 각 기법이 해결하는 병목과 대가로 치르는 것을 짝지어 설명한다.
- KV 캐시 크기를 공식으로 직접 계산하고, 이 값이 배치 크기·컨텍스트 길이에 왜 민감한지 설명한다.
- 배치 처리·프리필-디코딩 분리·프롬프트 캐싱·병렬 처리 전략 중 상황(지연 시간 우선인지 비용 우선인지)에 맞는 서비스 수준 최적화를 선택한다.
전체 흐름도
[ 추론 최적화 — 어디를 최적화하는가 ]
│
├─ ① 병목을 진단한다 (§1)
│ 연산 제약 vs 메모리 대역폭 제약 — 루프라인 차트·산술 강도로 구분
│ └→ 자기회귀 LM: 프리필(연산 제약) · 디코딩(메모리 대역폭 제약)
│
├─ ② 무엇을 잴 것인가 (§2)
│ 지연 시간(TTFT·TPOT) · 처리량과 굿풋(SLO 충족 여부까지) · 활용률(MFU·MBU)
│
├─ ③ 어디서 돌리는가 (§3)
│ 가속기(GPU·TPU·…) — 연산 성능(FLOP/s) · 메모리 계층(HBM·SRAM) · 전력(TDP)
│
▼
[ 최적화 두 축 — 무엇을 바꾸는가 ]
│
├─ ④ 모델 수준 (§4) — 모델 자체가 바뀐다, 출력 품질에 영향을 줄 수 있다
│ 모델 압축(양자화·증류·프루닝)
│ 자기회귀 디코딩 병목 극복(추측 디코딩·참조 기반 추론·병렬 디코딩)
│ 어텐션 메커니즘 최적화(KV 캐시 계산·관리·어텐션 재설계·커널)
│
└─ ⑤ 서비스 수준 (§5) — 모델은 그대로, 자원 배분 방식만 바뀐다
배치 처리(정적·동적·연속) · 프리필/디코딩 분리 · 프롬프트 캐싱 · 병렬 처리 전략
│
▼
[ 트레이드오프 — 지연 시간 ↔ 처리량 ↔ 비용 ↔ 모델 품질 ]
└→ 10장(아키텍처와 사용자 피드백)의 "캐시로 지연 시간 줄이기" 단계로 이어진다
0. 용어 사전
선행 용어 — 이 장을 읽기 전에
아래 5개는 앞선 장에서 다룬 개념이다. 낯설면 해당 장을 먼저 보면 좋다. 판정 기준 — 「이 말을 모르면 이 장을 못 읽는가」. 이 장에서 처음 설명하는 개념(KV 캐시·MFU·추측 디코딩 등)은 선행이 아니다 — 본문의 몫이므로 아래 표에 없다.
| 한글 용어 | 원문 영문명 | 의미 (정의 · 비유 · 본문 위치) |
|---|---|---|
| 트랜스포머 아키텍처 | Transformer Architecture | (선행) 어텐션 메커니즘만으로 시퀀스를 처리하는 아키텍처(2장 §2.1). 이 장이 다루는 대부분의 최적화 기법이 "트랜스포머라서" 생기는 병목(어텐션·자기회귀 디코딩)을 겨냥한다. 본문 §1·§4 |
| 어텐션 메커니즘 | Attention Mechanism | (선행) 쿼리·키·값 벡터로 각 입력 토큰에 얼마나 주목할지 계산하는 트랜스포머의 핵심 연산(2장 §2.1). 이 계산에 드는 키·값 벡터를 재사용하는 것이 이 장 §4.3의 KV 캐시다. 본문 §4.3 |
| 프리필과 디코드 | Prefill and Decode | (선행) 자기회귀 LM 추론의 두 단계 — 프리필은 입력 토큰을 병렬로 처리하고, 디코드는 출력 토큰을 하나씩 순차 생성한다(2장 §2.1). 이 장 §1.3이 이 둘의 연산 병목이 서로 다르다는 것부터 시작한다. 본문 §1.3·§2.1·§5.2 |
| 양자화 | Quantization | (선행) 모델의 수치 정밀도를 낮춰(예: 32비트→16비트) 메모리 사용량과 연산량을 줄이는 기법(7장 §4.2). 이 장 §4.1은 이를 "모델 압축"의 한 축으로 다시 불러온다. 본문 §4.1 |
| 모델 증류 | Model Distillation | (선행) 작은 학생 모델이 큰 교사 모델의 동작을 모방하도록 학습시키는 방법(8장 §6). 이 장 §4.1은 이를 모델 압축의 또 다른 축으로 다룬다. 본문 §4.1 |
이 장의 용어 전부 — 찾아보기
읽다가 막히면 여기서 찾는다. 위 선행 5개는 다시 적지 않는다. 본문 등장 순서로 둔다.
| 한글 용어 | 원문 영문명 | 의미 |
|---|---|---|
| 추론 서버 | Inference Server | 운영 환경에서 모델 추론을 실제로 실행하는 구성 요소. 여러 모델을 호스팅하고 하드웨어를 배정한다 |
| 추론 서비스 | Inference Service | 추론 서버를 감싸는 더 큰 시스템. 요청을 받아 적절한 곳으로 보내고 전처리도 담당한다 |
| 연산 제약 | Compute-Bound | 작업을 끝내는 시간이 연산량(FLOP)에 좌우되는 상태. 예: 암호 해독 |
| 메모리 대역폭 제약 | Memory Bandwidth-Bound | 작업을 끝내는 시간이 메모리↔프로세서 데이터 전송 속도에 좌우되는 상태 |
| 산술 강도 | Arithmetic Intensity | 메모리 1바이트에 접근할 때 수행하는 산술 연산 횟수. 이 값으로 연산 제약인지 대역폭 제약인지 가른다 |
| 루프라인 차트 | Roofline Chart | 산술 강도 대비 처리량을 그려, 작업이 연산 제약인지 대역폭 제약인지 보여주는 프로파일링 도표(Williams et al., 2009) |
| 온라인 API | Online API | 요청이 들어오면 바로 처리해 지연 시간을 최적화하는 추론 API |
| 배치 API | Batch API | 요청을 모아 처리해 비용을 최적화하는 추론 API. 처리에 초·분이 아니라 시간 단위가 걸릴 수 있다 |
| 스트리밍 | Streaming | 토큰이 생성되는 대로 하나씩 사용자에게 보내는 응답 방식. 첫 토큰까지 기다리는 시간을 줄인다 |
| TTFT | Time to First Token | 질의를 보낸 후 첫 번째 토큰이 나오기까지 걸리는 시간. 프리필 단계에 대응 |
| TPOT | Time per Output Token | 첫 토큰 이후 각 출력 토큰이 생성되는 데 걸리는 평균 시간. 디코딩 단계에 대응 |
| TBT·ITL | Time Between Tokens · Inter-Token Latency | 출력 토큰 사이사이 걸리는 시간을 재는 지표. TPOT와 비슷한 개념을 다른 이름으로 부른 것 |
| 공개까지의 시간 | Time to Publish | 에이전트가 계획·행동 등 내부 단계를 거친 뒤 사용자에게 실제로 보여주는 첫 토큰까지의 시간. TTFT보다 길 수 있다 |
| 백분위수 | Percentile | 전체 요청 중 특정 비율의 값. p50(중앙값)·p90·p95·p99로 지연 시간의 이상치를 본다 |
| 처리량 | Throughput | 추론 서비스가 초당 생성하는 출력 토큰 수(tokens/s) 또는 단위 시간당 완료 요청 수(RPS·RPM) |
| 굿풋 | Goodput | SLO(지연 시간 목표)를 만족하는 요청만 센 처리량. 네트워킹의 굿풋 개념을 LLM에 맞게 변형한 것 |
| SLO | Service-Level Objective | 서비스가 지켜야 할 목표 수치(예: TTFT 200ms 이하). 굿풋은 이 목표를 만족하는 요청 비율을 잰다 |
| 활용률 | Utilization | 전체 사용 가능한 용량 중 실제로 쓰이는 비율 |
| MFU | Model FLOP/s Utilization | 이론상 최대 FLOP/s 대비 실제 처리량의 비율. 엔비디아의 (오해받기 쉬운) GPU 활용률과 구분하기 위한 지표 |
| MBU | Model Bandwidth Utilization | 이론상 최대 메모리 대역폭 대비 실제로 쓰인 대역폭의 비율 |
| 가속기 | Accelerator | 특정 종류의 연산을 빠르게 처리하도록 만들어진 칩. GPU가 가장 널리 쓰이는 AI 가속기다 |
| FLOP/s | Floating Point Operations per Second | 칩이 초당 수행할 수 있는 부동소수점 연산 횟수. 연산 성능의 표준 단위 |
| 고대역폭 메모리(HBM) | High-Bandwidth Memory | GPU 전용 3D 적층 메모리. CPU의 DRAM보다 훨씬 빠르지만 비싸고 용량이 작다 |
| GPU 온칩 SRAM | On-Chip SRAM | 칩 안에 바로 들어 있는 가장 빠르지만 가장 작은 메모리(수십 MB급). L1·L2 캐시 등이 포함된다 |
| TDP | Thermal Design Power | 칩이 일반적인 작업을 할 때 냉각 시스템이 방출해야 하는 최대 열. 예상 전력 소모량의 대체 지표 |
| 모델 압축 | Model Compression | 모델 크기를 줄이는 기법들의 총칭. 양자화·증류·프루닝을 포함한다 |
| 프루닝 | Pruning | 예측에 별로 기여하지 않는 파라미터(또는 노드)를 제거하거나 0으로 만들어 희소하게 만드는 기법 |
| 추측 디코딩 | Speculative Decoding | 빠르지만 약한 초안 모델이 여러 토큰을 미리 만들고, 목표 모델이 이를 병렬로 검증·수락하는 디코딩 가속 기법 |
| 초안 모델 | Draft Model | 추측 디코딩에서 후보 토큰 시퀀스를 먼저 생성하는, 목표 모델보다 작고 빠른 모델 |
| 참조 기반 추론 | Inference with Reference | 입력 토큰 중 반복되는 구간을 모델이 새로 생성하는 대신 그대로 복사해 속도를 높이는 기법 |
| 병렬 디코딩 | Parallel Decoding | 순차적 의존성을 없애고 여러 미래 토큰을 동시에 생성한 뒤 검증하는 디코딩 가속 기법 계열 |
| 야코비 디코딩 | Jacobi Decoding | 병렬 디코딩에서 야코비 방법으로 생성된 토큰들을 반복적으로 검증·정제하는 방식(룩어헤드 디코딩이 사용) |
| 메두사 | Medusa | 원본 모델에 여러 디코딩 헤드를 추가해 여러 미래 위치의 토큰을 동시에 예측하고 트리 어텐션으로 검증하는 병렬 디코딩 기법 |
| KV 캐시 | KV Cache | 이전 토큰들의 키·값 벡터를 저장해 두어, 다음 토큰 생성 때 다시 계산하지 않고 재사용하게 하는 캐시 |
| 로컬 윈도우 어텐션 | Local Window Attention | 모든 이전 토큰이 아니라 인접한 고정 크기 윈도우 안의 토큰에만 어텐션을 적용하는 어텐션 재설계 기법 |
| 크로스 레이어 어텐션 | Cross-Layer Attention | 인접한 트랜스포머 레이어끼리 키·값 벡터를 공유해 KV 캐시를 줄이는 기법 |
| 멀티 쿼리 어텐션 | Multi-Query Attention | 여러 쿼리 헤드가 하나의 키·값 쌍 세트를 공유하는 어텐션 변형 |
| 그룹 쿼리 어텐션 | Group Query Attention | 쿼리 헤드를 여러 그룹으로 나누고 그룹 안에서만 키·값 쌍을 공유하는, 멀티 쿼리 어텐션의 절충안 |
| 페이지드 어텐션 | PagedAttention | KV 캐시를 연속되지 않은 블록으로 나눠 메모리 단편화를 줄이는 vLLM의 KV 캐시 관리 기법 |
| 플래시 어텐션 | FlashAttention | 어텐션 계산에 쓰이는 여러 연산을 하나로 융합해 속도를 높인 커널 |
| 커널 | Kernel | 특정 하드웨어 가속기에 맞춰 최적화한 저수준 코드. 벡터화·병렬화·루프 타일링·연산자 융합으로 속도를 높인다 |
| 컴파일러 | Compiler | 모델 연산을 대상 하드웨어가 실행할 수 있는 형태(전용 커널)로 로어링하는 도구. torch.compile·XLA·TensorRT 등 |
| 로어링 | Lowering | 모델 스크립트의 연산들을 대상 하드웨어와 호환되는 저수준 코드로 변환하는 과정 |
| 정적 배치 처리 | Static Batching | 정해진 수의 요청이 다 모일 때까지 기다렸다가 한 번에 처리하는 배치 방식 |
| 동적 배치 처리 | Dynamic Batching | 배치 크기 또는 최대 대기 시간 중 먼저 도달하는 조건에 따라 배치를 처리하는 방식 |
| 연속 배치 처리 | Continuous Batching | 응답이 끝난 자리에 새 요청을 바로 채워 넣어 배치를 계속 채우는 방식(인플라이트 배치 처리라고도 함) |
| 프리필-디코딩 분리 | Prefill-Decode Disaggregation | 연산 특성이 다른 프리필과 디코딩을 서로 다른 인스턴스에 배정해 자원 경쟁을 없애는 서비스 수준 기법 |
| 프롬프트 캐싱 | Prompt Caching | 여러 프롬프트에서 겹치는 부분(시스템 프롬프트 등)을 캐시해 반복 계산을 없애는 기법. 컨텍스트 캐시·프리픽스 캐시라고도 함 |
| 복제 병렬 처리 | Replica Parallelism | 모델의 복제본을 여러 개 만들어 요청을 병렬로 나눠 처리하는, 구현이 가장 간단한 병렬화 전략 |
| 모델 병렬 처리 | Model Parallelism | 하나의 모델을 여러 장치에 나눠 배치하는 전략. 텐서 병렬 처리와 파이프라인 병렬 처리가 대표적이다 |
| 텐서 병렬 처리 | Tensor Parallelism | 한 연산자에 속한 텐서를 여러 장치로 쪼개 그 연산자를 병렬로 실행하는 방식(연산자 내 병렬 처리) |
| 파이프라인 병렬 처리 | Pipeline Parallelism | 모델의 연산을 여러 단계로 나누고 각 단계를 다른 장치에 배정해, 마이크로 배치 단위로 겹쳐 실행하는 방식 |
| 컨텍스트 병렬 처리 | Context Parallelism | 입력 시퀀스 자체를 여러 장치로 나눠 각각 처리하는 병렬화 전략 |
| 시퀀스 병렬 처리 | Sequence Parallelism | 한 입력 처리에 필요한 여러 연산자(어텐션·피드포워드 등)를 서로 다른 장치에 나눠 배정하는 전략 |
1. 추론과 연산 병목
AI 모델의 생명주기는 학습과 추론 두 단계로 나뉜다. 모델을 직접 학습·파인튜닝하지 않는다면 실무에서 다루는 것은 대부분 추론이다. 운영 환경에서 모델 추론을 실제로 실행하는 구성 요소가 추론 서버다. 추론 서버는 여러 모델을 호스팅하고 필요한 하드웨어를 배정하며, 요청(사용자 프롬프트)이 들어오면 리소스를 할당해 모델을 실행하고 결과를 반환한다. 추론 서버는 더 큰 시스템인 추론 서비스의 한 부분이다 — 추론 서비스는 요청을 적절한 곳으로 보내고, 추론 서버에 도달하기 전 전처리도 담당한다. 오픈AI나 구글이 제공하는 모델 API가 추론 서비스의 예다. 이런 API를 사용만 한다면 이 장의 기법을 직접 구현할 일은 거의 없지만, 모델을 직접 호스팅한다면 추론 서비스 개발·최적화·유지보수를 모두 떠맡아야 한다.
1.1 연산 병목 두 가지
최적화는 병목을 찾아 해결하는 일이다. 추론 서버가 마주치는 주요 연산 병목은 두 가지다. 연산 제약은 작업을 끝내는 시간이 연산량(FLOP)에 좌우되는 경우다(예: 암호 해독). 메모리 대역폭 제약은 메모리와 프로세서 사이의 데이터 전송 속도가 병목이 되는 경우다(예: CPU 메모리의 데이터를 GPU로 옮겨 학습할 때). 두 개념은 Williams 등(2009)의 〈Roofline〉 논문에서 처음 소개됐고, 수학적으로는 산술 강도(메모리 1바이트에 접근할 때 수행하는 산술 연산 횟수)로 어느 쪽 제약인지 가른다. 엔비디아 엔사이트 같은 프로파일링 도구의 루프라인 차트(지붕 모양이라 이렇게 부른다)로 작업이 연산 제약인지 대역폭 제약인지 시각적으로 확인할 수 있다.
참고 — "메모리 제약"이라는 말의 모호함. 시스템 쪽 출신(최적화·GPU 엔지니어)은 "메모리 제약"을 대역폭 제약의 의미로 쓰는 경향이 있고, AI 쪽 출신(ML·AI 엔지니어)은 같은 말을 메모리 용량 제약(흔히 겪는 OOM 오류)의 의미로 쓰는 경향이 있다. 다만 용량 제약은 작업을 잘게 나누면(예: 모델을 GPU·CPU 메모리에 나눠 저장) 해결되는 경우가 많고, 그 대가가 결국 CPU-GPU 간 데이터 전송 속도이므로 용량 제약도 근본적으로는 대역폭 문제로 귀결된다.
최적화 기법마다 해결하는 병목이 다르다. 연산 제약 작업은 칩을 더 많이 분산시키거나 FLOP/s가 높은 칩으로 속도를 높이고, 메모리 대역폭 제약 작업은 대역폭이 넓은 칩으로 속도를 높인다. 모델 구조에 따라서도 병목이 갈린다 — 스테이블 디퓨전 같은 이미지 생성 추론은 보통 연산 제약이고, 자기회귀 언어 모델 추론은 보통 메모리 대역폭 제약이다.
1.2 프리필과 디코딩의 병목
2장 §2.1에서 설명했듯이 트랜스포머 기반 언어 모델의 추론은 프리필과 디코드 두 단계로 나뉜다. 프리필은 입력 토큰들을 병렬로 처리하는 단계로, 한 번에 처리할 수 있는 토큰 수는 하드웨어가 정해진 시간에 실행할 수 있는 연산량에 달려 있다 — 그래서 프리필은 연산 제약이다. 디코딩은 출력 토큰을 하나씩 생성하는 단계로, 매 단계마다 거대한 가중치 행렬을 GPU 메모리에서 불러와야 하므로 메모리 대역폭 제약이다. 프리필과 디코딩은 연산 방식이 근본적으로 달라서, 운영 환경에서는 이 둘을 아예 다른 머신에서 분리해 돌리는 경우가 많다(§5.2). LLM 추론 서버에서 병목이 프리필 쪽인지 디코딩 쪽인지는 컨텍스트 길이·출력 길이·배치 요청 방식에 따라 달라진다 — 컨텍스트가 길수록 보통 메모리 대역폭 제약이 커지는데, 이 장 뒷부분(§4.3)에서 다룰 KV 캐시 최적화 기법들로 이 병목을 완화할 수 있다. 집필 시점에는 트랜스포머 아키텍처가 널리 쓰이고 현재 가속기 기술의 한계 때문에 AI·데이터 작업 대부분이 메모리 대역폭 제약을 받지만, 소프트웨어·하드웨어가 발전하면 연산 제약으로 옮겨갈 수 있다.
1.3 온라인 API와 배치 API
많은 모델 제공업체가 온라인 API(지연 시간 최적화 — 요청이 들어오면 바로 처리)와 배치 API(비용 최적화 — 요청을 모아 처리)를 함께 제공한다. 예를 들어 집필 시점에 구글 제미나이와 오픈AI 모두 배치 API를 50% 할인된 가격에 제공하지만, 처리 시간은 초·분이 아니라 시간 단위로 걸린다. 챗봇·코드 자동완성처럼 고객 대면 서비스는 낮은 지연 시간이 필요해 온라인 API를 쓰고, 합성 데이터 생성·정기 보고서 작성·신규 고객 온보딩·모델 마이그레이션·대규모 개인화 추천처럼 지연 시간 요구가 느슨한 작업은 배치 API가 적합하다.
참고 — 기존 ML의 배치 추론과 다르다. 기존 ML에서 배치 추론은 요청이 들어오기 전에 예측을 미리 연산해 두는 것(추천 시스템처럼 입력 범위가 정해진 경우에 가능)을 뜻했다. 파운데이션 모델은 사용자가 자유롭게 입력하므로 모든 프롬프트를 미리 예측할 수 없다 — 다만 시스템 프롬프트처럼 미리 알 수 있는 부분은 프롬프트 캐싱(§5.3)의 대상이 된다.
API는 보통 완성된 응답을 통째로 반환하지만, 자기회귀 디코딩은 응답 하나를 완성하는 데 시간이 걸릴 수 있어 많은 온라인 API가 토큰이 생성되는 대로 하나씩 보내는 스트리밍 모드를 제공한다. 첫 토큰까지 기다리는 시간을 줄여 주지만, 사용자에게 보여주기 전에 응답 전체를 평가할 수 없어 나쁜 응답이 노출될 위험이 커진다는 단점이 있다(다만 위험이 발견되면 나중에 수정·삭제는 가능하다).
2. 추론 성능을 재는 지표
최적화를 시작하기 전에 어떤 지표를 개선해야 하는지부터 알아야 한다. 사용자 관점에서는 지연 시간이 가장 중요하고(응답 품질은 모델 자체의 문제이지 추론 서비스의 문제가 아니다), 애플리케이션 개발자는 운영 비용을 결정하는 처리량·활용률도 함께 봐야 한다.
2.1 지연 시간 — TTFT·TPOT·TBT
지연 시간은 사용자가 질의를 보낸 시점부터 완전한 응답을 받기까지 걸리는 시간이다. 자기회귀 생성, 특히 스트리밍 모드에서는 이를 여러 지표로 나눌 수 있다. TTFT(첫 토큰까지 걸리는 시간)는 프리필 단계에 대응하고 입력 길이에 좌우된다 — 대화형 챗봇은 TTFT가 즉시 나와야 하지만, 긴 문서 요약은 좀 더 기다려도 된다. TPOT(출력 토큰당 시간)는 디코딩 단계에 대응한다 — 토큰당 100ms면 1,000토큰 응답에 100초가 걸린다. 스트리밍에서는 TPOT가 사람의 읽기 속도보다는 빨라야 하지만 훨씬 빠를 필요는 없다 — 아주 빠른 독자도 토큰당 약 120ms(초당 6~8토큰)로 읽으므로 그 정도면 충분하다. 비슷한 지표로 출력 토큰 사이사이의 시간을 재는 TBT·ITL이 있다. 전체 지연 시간은 TTFT + TPOT × 출력 토큰 수로 계산된다.
전체 지연 시간이 같아도 TTFT와 TPOT의 배분이 다르면 사용자 경험이 달라진다 — 연산 자원을 디코딩에서 프리필로 옮기거나 그 반대로 하면 한쪽을 줄이는 대신 다른 쪽이 늘어난다. 특히 생각의 사슬(CoT)·에이전트 방식에서는 모델이 내부적으로 계획·행동 같은 중간 단계를 거치고 그 결과는 사용자에게 보이지 않으므로, 사용자가 실제로 보는 첫 토큰까지의 시간은 모델이 내부적으로 첫 토큰을 낸 시점보다 훨씬 길다 — 일부 팀은 이를 구분해 공개까지의 시간이라 부른다.
참고 — 평균은 지연 시간을 왜곡한다. TTFT 값이
100, 102, 100, 100, 99, 104, 110, 90, 3000, 95(ms, 10개 요청)라면 평균은 390ms로 서비스가 실제보다 훨씬 느려 보인다. 네트워크 오류나 유난히 긴 프롬프트 같은 원인으로 이상치 하나가 평균을 크게 왜곡했을 뿐이다. 그래서 지연 시간은 백분위수(p50=중앙값, p90·p95·p99)로 보는 편이 더 도움이 된다 — 요청이 많을수록 평균은 이상치에 취약해진다.
2.2 처리량과 굿풋
처리량은 추론 서비스가 모든 사용자·요청을 통틀어 초당 몇 개의 출력 토큰을 만드는지 잰다(tokens/s, 종종 TPS). 프리필(입력 처리)과 디코딩(출력 생성)은 병목 지점이 다르므로 입력·출력 처리량을 따로 계산해야 하며, 보통 "처리량"은 출력 토큰 기준을 뜻한다. 완료 요청 개수로도 잴 수 있는데(RPS·RPM), 파운데이션 모델 응답은 완료에 몇 초씩 걸릴 수 있어 분당 완료 요청 수(RPM)를 더 많이 쓴다.
처리량은 비용과 직결된다 — 시스템 연산 비용이 시간당 2달러이고 처리량이 초당 100토큰이라면, 출력 토큰 100만 개당 약 5.556달러가 든다. 요청 하나가 평균 200개 출력 토큰을 낸다면 1,000개 요청의 디코딩 비용은 1.11달러다. 프리필 비용도 비슷하게 계산할 수 있어(시간당 2달러 하드웨어로 분당 100개 요청을 프리필한다면 1,000개 요청 프리필은 0.33달러), 요청당 총비용은 두 비용의 합(이 예에서는 1.44달러)이다. 다만 토크나이저가 모델마다 달라 토큰 개수 자체의 의미가 다르므로, 서로 다른 서비스의 처리량을 직접 비교하기보다는 요청당 비용으로 비교하는 편이 더 정확하다.
지연 시간과 처리량 사이에는 트레이드오프가 있다 — 배치 처리는 처리량을 높이지만 지연 시간을 늘린다. 링크드인의 2024년 회고에 따르면 TTFT·TPOT를 조금 희생하면 처리량을 2~3배까지 올릴 수 있는 경우가 많다. 처리량과 비용만으로 서비스를 판단하면 사용자 경험이 나빠질 수 있어, 일부 팀은 굿풋이라는 지표에 집중한다 — 굿풋은 소프트웨어 수준 목표(SLO, 예: TTFT 200ms 이하·TPOT 100ms 이하)를 만족하는 초당(분당) 요청 수만 센다. 서비스가 분당 100개 요청을 처리해도 그중 30개만 SLO를 만족한다면 굿풋은 30 RPM일 뿐이다 — 처리량이 높아도 굿풋은 낮을 수 있다는 뜻이다.
2.3 활용률 — MFU·MBU
활용률은 전체 사용 가능한 용량 중 실제로 쓰이는 비율을 잰다. 자주 쓰이지만 오해받는 지표가 nvidia-smi가 보여주는 "GPU 활용률"이다 — 이는 GPU가 작업을 처리하는 시간의 비율일 뿐, 그 작업이 GPU 성능을 얼마나 알차게 쓰는지는 말해 주지 않는다. 초당 100개 연산이 가능한 GPU가 초당 1개 연산만 하고 있어도 nvidia-smi 기준 활용률은 100%로 나올 수 있다. 그래서 이와 구분해 MFU(Model FLOP/s Utilization)를 쓴다 — 이론상 최고 FLOP/s로 달성 가능한 최대 처리량 대비 실제 처리량(tokens/s)의 비율이다. 칩의 광고된 최대 FLOP/s로는 초당 100토큰을 낼 수 있는데 실제로 초당 20토큰만 낸다면 MFU는 20%다. 마찬가지로 메모리 대역폭이 얼마나 알차게 쓰이는지는 MBU(Model Bandwidth Utilization)로 잰다.
실무 예제 — MBU 계산. LM 추론에 쓰이는 메모리 대역폭은
파라미터 수 × 파라미터당 바이트 × tokens/s로 계산하고, MBU는 이 값을 이론적 최대 대역폭으로 나눈 것이다(원문 예시).```text 70억 파라미터 모델, FP16(파라미터당 2바이트), 초당 100토큰 사용 대역폭 = 7B × 2 × 100 = 1,400GB/s
A100-80GB의 이론적 메모리 대역폭 = 2TB/s MBU = 1,400GB/s ÷ 2TB/s = 70% ```
이 계산이 보여주는 것 — 파라미터당 바이트 수가 적을수록(양자화, §4.1) 같은 처리량을 내는 데 필요한 대역폭이 줄어든다. 처리량과 MBU·MFU의 관계는 대체로 선형이라, 처리량만으로 이 둘을 어림잡기도 한다.
좋은 MFU·MBU 수준은 모델·하드웨어·작업에 따라 다르다. 연산 제약 작업은 보통 MFU가 높고 MBU가 낮으며, 대역폭 제약 작업은 그 반대다. 학습은 작업 패턴이 예측 가능해 더 효율적으로 최적화할 수 있어 학습 MFU가 보통 추론 MFU보다 높고, 추론에서는 연산 위주인 프리필의 MFU가 메모리 위주인 디코딩의 MFU보다 높다. 모델 학습에서는 집필 시점 기준 MFU 50% 이상을 일반적으로 좋다고 본다(하드웨어에 따라 쉽지 않을 수 있다). Chowdhery 등(2022)의 PaLM 논문은 GPT-3(V100, MFU 21.3%)·고퍼(TPU v3, 32.5%)·MT-NLG(A100, 30.2%)·PaLM(TPU v4, 46.2%)의 MFU 예시를 보여준다. 다만 활용률이 높다고 목표를 달성한 것은 아니다 — 진짜 중요한 것은 작업을 더 빠르고 저렴하게 처리하는 것이지, 활용률이 가장 높은 칩을 고르는 것이 아니다.
3. AI 가속기 이해하기
소프트웨어가 얼마나 빠르고 저렴하게 도는지는 어떤 하드웨어에서 실행되느냐에 달려 있다. 이 절은 추론 관점에서 가속기를 살펴보지만, 학습 과정에도 그대로 적용된다.
3.1 가속기와 딥러닝의 얽힌 역사
AI 모델과 하드웨어의 발전은 늘 함께 얽혀 왔다 — 1960~1970년대 첫 AI 빙하기의 한 원인은 강력한 컴퓨터의 부재였고, 2012년 딥러닝이 다시 주목받은 것도 알렉스넷이 신경망 학습에 GPU를 성공적으로 쓴 첫 사례였기 때문이다(그 직전 연구는 비슷한 규모의 모델 학습에 수천 개의 CPU가 필요하다고 밝혔다). 몇 개의 GPU만으로 학습이 가능해지면서 딥러닝 연구 붐이 일었다.
가속기는 특정 종류의 연산을 빠르게 처리하도록 만들어진 칩이다. CPU는 강력한 코어 몇 개로 범용 작업(운영체제 실행·I/O·복잡한 순차 처리)에 강하고, GPU는 수천 개의 작고 약한 코어로 병렬화하기 쉬운 대량의 독립 연산(그래픽 렌더링·ML의 행렬 곱셈)에 강하다. 엔비디아 GPU의 성공을 뒤따라 AMD GPU, 구글의 TPU, 인텔의 하바나 가우디, 그래프코어의 IPU, 그로크의 LPU 등 다양한 가속기가 등장했다. 최근에는 학습·추론을 모두 처리하는 범용 칩 외에 추론 전용 칩이 늘고 있다 — Desislavov 등(2023)에 따르면 이미 배포돼 운영 중인 AI 시스템은 ML 관련 비용의 최대 90%를 추론이 차지한다. 추론용 칩은 학습용 칩과 달리 대용량 메모리보다 낮은 정밀도·빠른 메모리 접근에 최적화되는 경우가 많다(애플 Neural Engine, AWS Inferentia, 메타 MTIA 등).
3.2 칩의 핵심 사양 — 연산 성능·메모리·전력
칩을 평가할 때 중요한 세 가지 특성은 연산 성능, 메모리 크기와 대역폭, 전력 소모다.
연산 성능은 보통 FLOP/s로 잰다. 정밀도가 높을수록 같은 시간에 수행 가능한 연산은 줄어든다(7장 §4.2의 수치 표현 방식 참고) — 엔비디아 H100 SXM은 TF32 989 TFLOPS, BFLOAT16·FP16 각 1,979 TFLOPS, FP8 3,958 TFLOPS(밀집 연산 기준)다.
메모리 크기와 대역폭은 세 단계 계층으로 나뉜다. ① CPU 메모리(DRAM)는 대역폭이 가장 낮고(25~50GB/s) 크기는 노트북 16~64GB부터 고급 워크스테이션 1TB 이상까지 다양하다. ② GPU 고대역폭 메모리(HBM)는 GPU 가까이 둬 훨씬 빠르게(256GB/s~1.5TB/s 이상) 접근하며, 소비자용 GPU는 약 24~80GB를 갖는다. ③ GPU 온칩 SRAM은 L1·L2(일부는 L3) 캐시를 포함해 10TB/s를 넘는 속도를 내지만 크기는 40MB 이하로 작다. GPU 최적화의 상당 부분이 이 메모리 계층을 얼마나 잘 활용하느냐에 달려 있는데, 파이토치·텐서플로 같은 프레임워크는 아직 메모리 접근을 세밀하게 제어하지 못해 CUDA·트리톤·ROCm 같은 저수준 GPU 프로그래밍 언어가 쓰인다.
전력 소모는 칩 안의 수십억 개 트랜지스터가 상태를 바꾸며 에너지를 쓰고 열을 내는 데서 생긴다(A100은 약 540억 개, H100은 약 800억 개의 트랜지스터를 가진다). 이 열을 식히는 냉각 시스템도 전기를 쓰므로 데이터센터 전체 에너지 소비가 커진다 — H100이 1년 내내 최대 성능으로 돌면 약 7,000kWh를 쓰는데, 이는 미국 가정의 연간 평균 전력 사용량(약 10,000kWh)에 맞먹는다. 가속기는 보통 최대 전력 소모량이나 TDP(칩이 일반 작업을 할 때 냉각 시스템이 방출해야 하는 최대 열)로 전력 소모를 표시한다.
3.3 가속기 선택 기준
어떤 가속기를 쓸지는 작업 종류에 달려 있다 — 연산 중심 작업이라면 FLOP/s가 높은 칩을, 메모리 중심 작업이라면 대역폭이 넓고 용량이 큰 칩을 고른다. 칩을 살 때는 세 가지 질문이 핵심이다. ① 이 하드웨어로 원하는 작업을 실행할 수 있는가? ② 실행하는 데 얼마나 걸리는가? ③ 비용이 얼마나 드는가? FLOP/s·메모리 크기·대역폭이 앞의 두 질문에 답하고, 마지막 질문은 클라우드 사용량 기반 과금이나 구입 비용+전력비 합산으로 답한다.
4. 모델 수준 최적화
모델 수준 최적화는 모델 자체를 수정해 효율을 높이는 것이 목표이며, 그래서 모델 성능이 바뀔 수 있다. 실제로 같은 라마 모델이라도 추론 서비스 제공업체마다 적용하는 최적화 기법에 따라 벤치마크 성능이 미세하게 달라진다(Cerebras, 2024). 집필 시점의 파운데이션 모델 대부분은 트랜스포머 아키텍처의 자기회귀 언어 모델이며, 이들을 리소스 집약적으로 만드는 세 가지 특성 — 모델 크기, 자기회귀 디코딩, 어텐션 메커니즘 — 이 이번 절의 세 갈래다.
4.1 모델 압축 — 양자화·증류·프루닝
모델 압축은 모델 크기를 줄여 속도까지 높이는 기법들을 말한다. 양자화(7장 §4.2 — 정밀도를 낮춰 메모리 사용량을 줄인다)와 모델 증류(8장 §6 — 작은 모델이 큰 모델의 동작을 모방하도록 학습시킨다)는 이미 앞 장에서 다뤘다. 증류가 "더 적은 파라미터로 큰 모델의 동작을 잡아낼 수 있다"는 것을 보여준다면, 자연스러운 질문이 하나 나온다 — 큰 모델 안에 전체 동작을 담아내는 파라미터의 부분집합이 이미 존재하지 않을까? 이것이 프루닝의 핵심 아이디어다.
프루닝에는 두 가지 뜻이 있다. 신경망 노드 전체를 제거해 아키텍처와 파라미터 개수를 줄이는 방식과, 예측에 기여가 적은 파라미터를 찾아 0으로 만들어(전체 개수는 그대로 두고 0이 아닌 개수만 줄여) 모델을 희소하게 만드는 방식이다. 후자는 저장 공간을 줄이고 연산도 빠르게 하며, 프루닝 후 추가 파인튜닝으로 성능을 회복할 수도 있다. Frankle과 Carbin(2019)은 프루닝으로 0이 아닌 파라미터를 90% 이상 줄이면서도 정확도를 유지한 사례를 보였다. 다만 집필 시점에는 프루닝이 실제로 많이 쓰이지는 않는다 — 원본 아키텍처에 대한 깊은 이해가 필요해 다루기 어렵고, 프루닝이 만드는 희소 모델의 이점을 모든 하드웨어가 잘 살리도록 설계돼 있지도 않기 때문이다. 그래서 이 분야에서 가장 인기 있는 방법은 여전히 가중치 전용 양자화 — 쓰기 쉽고 대부분의 모델에 바로 통하며 효과가 크다(다만 값 하나당 1비트보다 낮출 수는 없어 한계에 가까워지고 있다).
4.2 자기회귀 디코딩 병목 극복하기
자기회귀 언어 모델은 토큰을 하나씩 순서대로 생성한다. 토큰 하나에 100ms가 걸리면 100토큰 응답에 10초가 걸리고, 여러 API 업체에서 출력 토큰은 입력 토큰보다 2~4배 비용이 든다 — 자기회귀 생성 과정을 조금만 개선해도 사용자 경험이 크게 좋아질 수 있는 이유다.
추측 디코딩은 더 빠르지만 성능이 낮은 초안 모델로 토큰 시퀀스를 만들고, 목표 모델(원래 쓰려던 모델)이 이를 병렬로 검증하는 방식이다. 절차는 ① 초안 모델이 K개 토큰을 생성 ② 목표 모델이 이 K개를 병렬로 검증 ③ 처음 예측이 엇갈리는 지점 바로 앞까지만 수락 ④ 그 지점에서 목표 모델이 토큰 하나를 직접 생성하고 다시 ①로 돌아간다. 모든 초안 토큰이 거부되면 목표 모델이 직접 생성한 토큰 1개만 나오고, 모두 수락되면 K+1개(초안 K개+목표 1개)가 한 번에 나온다. 이 방식이 성립하는 이유는 세 가지다 — 검증은 병렬화되지만 생성은 순차적이라 검증이 직접 생성보다 빠르고(사실상 디코딩을 프리필 방식으로 바꾸는 효과), 예측하기 쉬운 토큰을 잘 맞추는 약한 초안 모델을 고르면 수락률이 오르며, 디코딩은 메모리 대역폭 제약이라 보통 남는 FLOP을 검증에 쓸 수 있다. 딥마인드는 친칠라-70B의 디코딩을 위해 같은 아키텍처의 40억 파라미터 초안 모델을 학습시켰는데, 초안 모델이 8배 빠르게 토큰을 생성해(1.8ms 대 14.1ms) 응답 품질 저하 없이 전체 지연 시간을 절반 이상 줄였다(Chen et al., 2023). vLLM·TensorRT-LLM·llama.cpp 같은 유명 추론 프레임워크에 이미 구현돼 있다.
참조 기반 추론은 응답이 입력의 토큰을 그대로 반복해야 하는 경우(문서 인용, 코드 버그 수정처럼 원본을 조금만 바꿔 재사용하는 경우)에, 모델로 초안 토큰을 만드는 대신 입력에서 초안 토큰을 가져오는 방식이다. 추가 모델이 필요 없다는 점이 추측 디코딩과 다르지만, 검색 시스템·코딩·멀티 턴 대화처럼 컨텍스트와 출력이 상당히 겹치는 시나리오에서만 유용하다(Yang et al., 2023 — 해당 활용 사례에서 2배 속도 향상 주장).
병렬 디코딩은 순차적 의존성 자체를 없애려 한다 — 이미 나온 토큰들만으로 다음 몇 개 토큰까지 충분히 예측할 수 있는 경우가 많다는 통찰에서 출발한다("the cat sits" 다음 단어는 모르지만 그다음 단어가 "the"일 것은 예측할 수 있다). 병렬 토큰은 같은 디코더로 만들 수도 있고(룩어헤드 디코딩 — 야코비 방법으로 검증), 별도 디코딩 헤드로 만들 수도 있다(메두사 — 각 헤드가 특정 미래 위치를 예측하도록 학습되고, 트리 기반 어텐션으로 후보를 검증·통합한다. 엔비디아는 메두사로 라마 3.1 토큰 생성을 최대 1.9배 향상시켰다고 보고했다). 다만 이렇게 순차적이지 않게 생성된 토큰들은 서로 앞뒤가 맞는지 검증이 필요하며, 이 검증·통합 절차가 병렬 디코딩 구현을 까다롭게 만든다.
4.3 어텐션 메커니즘 최적화
2장 §2.1에서 설명했듯, 다음 토큰을 생성하려면 이전 모든 토큰의 키·값 벡터가 필요하다. 매 단계 이를 다시 계산하는 대신 이전 단계에서 계산해 둔 값을 재사용하는 캐시가 KV 캐시다 — 가장 최근 토큰의 키·값만 새로 계산해 캐시에 추가하면 된다.
참고 — KV 캐시는 추론에서만 쓰인다. 학습할 때는 시퀀스의 모든 토큰을 이미 알고 있어 다음 토큰 예측을 한꺼번에 계산할 수 있으므로 캐시가 필요 없다.
토큰 하나를 생성하는 데 필요한 어텐션 연산량은 시퀀스 길이의 제곱에 비례해 늘지만, KV 캐시 크기는 시퀀스 길이에 선형으로 늘고 배치 크기가 클수록 함께 커진다. Pope 등(2022)에 따르면 멀티헤드 어텐션을 가진 500B+ 모델은 배치 크기 512·컨텍스트 길이 2,048에서 KV 캐시가 총 3TB(모델 가중치 크기의 3배)에 달한다. KV 캐시 크기는 결국 하드웨어 저장 공간의 제약을 받아 롱 컨텍스트 애플리케이션의 병목이 되고, 캐시가 크면 메모리에 불러오는 데도 시간이 걸려 빠른 응답이 중요한 애플리케이션에 문제가 된다.
최적화하지 않았을 때 KV 캐시가 쓰는 메모리는 다음과 같이 계산한다.
KV 캐시 메모리 = 2 × B × S × L × H × M
B: 배치 크기
S: 시퀀스 길이
L: 트랜스포머 레이어 개수
H: 모델 차원
M: 캐시 값 하나를 저장하는 데 필요한 바이트 수(FP16=2바이트, FP32=4바이트 등)
(2를 곱하는 것은 키·값 두 벡터를 모두 저장하기 때문이다)
실무 예제 — 라마 2-13B의 KV 캐시 크기 계산(원문 예시, 수치 정정). 라마 2-13B는 레이어 40개, 모델 차원 5,120이다. 배치 크기 32, 시퀀스 길이 2,048, 값 하나당 2바이트(FP16)라면,
text 2 × 32 × 2,048 × 40 × 5,120 × 2바이트 = 53,687,091,200바이트 ≈ 53.7GB(10억 바이트 기준) — 약 50GiB(2^30바이트 기준)최적화 없이도 13B급 모델 하나가 배치 32·컨텍스트 2K만으로 수십 GB의 캐시를 요구한다는 뜻이며, 컨텍스트가 길어질수록(선형으로), 배치가 커질수록(선형으로) 이 값은 그만큼 불어난다.
원문과의 차이 — 원문은 이 계산 결과를 "254GB"로 인쇄하고 있다. 그러나 위 공식에 원문이 제시한 값(B=32, S=2,048, L=40, H=5,120, M=2바이트)을 그대로 넣으면 53,687,091,200바이트, 즉 약 53.7GB가 나온다(254GB는 공식·변수 값 어느 쪽으로도 재현되지 않는 인쇄 오류로 판단된다). 이 학습자료는 공식대로 계산한 값을 싣는다.
어텐션 메커니즘을 더 효율적으로 만드는 기법은 크게 세 갈래다. 어텐션 메커니즘 재설계는 학습·파인튜닝 단계에서만 적용할 수 있다(아키텍처 자체를 바꾸므로) — 로컬 윈도우 어텐션(인접한 고정 윈도우에만 어텐션을 적용해, 평균 시퀀스 10,000토큰에 윈도우 1,000토큰이면 KV 캐시가 10배 준다. 글로벌 어텐션과 섞어 쓸 수 있다), 크로스 레이어 어텐션(인접 레이어끼리 키·값을 공유 — 레이어 3개가 공유하면 캐시가 3분의 1로), 멀티 쿼리 어텐션(쿼리 헤드들이 키·값을 공유), 그룹 쿼리 어텐션(쿼리 헤드를 그룹으로 나눠 그룹 안에서만 공유 — 유연성과 절감의 절충)이 그 예다. Character.AI는 평균 대화가 180개 메시지에 달하는 자사 서비스에서 멀티 쿼리 어텐션·로컬/글로벌 어텐션 번갈아 쓰기·크로스 레이어 어텐션 세 기법으로 KV 캐시를 20배 이상 줄였다고 보고했다(2024).
KV 캐시 크기 최적화는 저장 공간 관리 자체를 개선한다 — vLLM의 페이지드 어텐션은 캐시를 연속되지 않은 블록으로 나눠 메모리 단편화를 줄이고 유연하게 공유한다(Kwon et al., 2023). KV 캐시 양자화·적응형 압축·선택적 캐시 같은 기법도 있다.
커널 작성은 어텐션 연산 자체를 하드웨어에 맞게 최적화한다. 커널은 GPU·TPU 같은 특정 가속기에 맞춘 저수준 코드로, 캐시·글로벌 메모리·공유 메모리·레지스터 등 메모리 계층 구조를 깊이 이해해야 작성할 수 있고 CUDA·트리톤·ROCm 같은 언어로 짜인다. 가장 널리 알려진 어텐션 커널이 플래시 어텐션(Dao et al., 2022)이다 — 여러 연산을 하나로 융합해 더 빠르게 만든다. 커널 작성에 자주 쓰이는 네 가지 기법은 벡터화(여러 데이터를 한꺼번에 처리), 병렬화(독립적인 덩어리로 나눠 동시 처리), 루프 타일링(하드웨어 메모리·캐시 레이아웃에 맞게 데이터 접근 순서를 최적화), 연산자 융합(여러 연산자를 한 패스로 합쳐 불필요한 메모리 접근을 줄임 — 모델·아키텍처를 깊이 알아야 해 가장 손이 많이 간다)이다. 새 하드웨어가 나올 때마다 새 커널이 필요하다 — 플래시 어텐션도 원래 A100용이었고 이후 H100용 플래시 어텐션-3가 따로 나왔다. 모델 스크립트를 대상 하드웨어가 실행할 수 있는 형태로 바꾸는 과정을 로어링이라 하고, 이를 수행하는 도구가 컴파일러다(torch.compile·XLA/OpenXLA·TensorRT 등). 파이토치 팀은 라마-7B에 torch.compile로 커널을 컴파일하고, 가중치를 INT8로, 다시 INT4로 양자화하는 세 단계로 처리량을 계속 끌어올렸다(PyTorch, 2023) — 다만 이런 최적화 조합이 모델 출력 품질에 정확히 어떤 영향을 주는지는 아직 명확히 밝혀지지 않았다.
5. 추론 서비스 수준 최적화
서비스 수준 기법은 대부분 리소스 관리에 집중한다. 한정된 연산·메모리와 계속 변하는 작업량이 있을 때, 목표는 지연 시간과 비용을 최적화하도록 자원을 효율적으로 배분하는 것이다. 모델 수준 기법과 달리 서비스 수준 기법은 모델을 수정하지 않고 출력 품질도 바꾸지 않아야 한다.
5.1 배치 처리
여러 요청을 비슷한 시간에 함께 처리하면 서비스 처리량을 크게 높일 수 있다 — 각자 자기 차로 가는 대신 버스에 함께 태우는 것과 같다(버스는 많이 실어 나르지만 개인 이동 시간은 늘 수 있다). 배치 처리는 세 방식이 있다. 정적 배치 처리는 정해진 수의 요청이 다 모일 때까지 기다렸다가 한 번에 처리한다(모든 자리가 찰 때까지 기다리는 버스) — 첫 요청이 마지막 요청의 도착 시점까지 지연되는 단점이 있다. 동적 배치 처리는 배치 크기 또는 최대 대기 시간(예: 4개 요청 또는 100ms) 중 먼저 도달하는 조건에 따라 처리한다(정해진 시간에 출발하거나 만석이면 출발하는 버스) — 지연 시간은 통제되지만 배치가 항상 꽉 차 있지는 않아 연산 낭비가 생길 수 있다. 기본적인 배치 구현은 배치 안 모든 요청이 끝나야 응답을 반환하므로, 응답 토큰 10개짜리 요청이 1,000개짜리 요청과 같은 배치에 있으면 짧은 응답도 긴 응답이 끝날 때까지 기다려야 한다. 연속 배치 처리(Orca, Yu et al., 2022)는 이 문제를 풀어 배치 안에서 응답이 끝난 자리에 바로 새 요청을 채워 넣는다(승객을 내려준 자리에 바로 다른 승객을 태우는 버스) — 인플라이트 배치 처리라고도 부른다.
5.2 프리필과 디코딩 분리
프리필은 연산 집약적이고 디코딩은 메모리 대역폭 집약적이라, 같은 장비에서 둘 다 처리하면 리소스 경쟁이 생겨 TTFT·TPOT가 모두 느려질 수 있다 — 이미 연산 용량 근처에서 디코딩을 처리 중인 GPU에 새 질의(프리필 작업 포함)를 추가하면, 그 프리필이 기존 디코딩 작업들의 TPOT를 늦춘다. 그래서 흔한 최적화가 프리필-디코딩 분리다. DistServe(Zhong et al., 2024)·Inference Without Interference(Hu et al., 2024) 같은 연구는 프리필·디코딩을 서로 다른 인스턴스(GPU)에 배정하면 지연 시간 요구사항을 지키면서도 처리 요청량을 크게 늘릴 수 있음을 보였다 — 최신 GPU 클러스터의 NVLink 같은 고대역폭 연결에서는 프리필→디코딩 인스턴스 간 중간 상태 전송의 통신 오버헤드도 크지 않다. 프리필·디코딩 인스턴스 비율은 워크로드(입력이 길수록 프리필 비중↑)와 지연 시간 목표(TTFT냐 TPOT냐)에 따라 2:1~4:1(TTFT 우선, 긴 입력) 또는 1:2~1:1(TPOT 우선, 짧은 입력) 사이에서 정해진다.
5.3 프롬프트 캐싱
애플리케이션의 여러 프롬프트에는 겹치는 부분(대표적으로 시스템 프롬프트)이 있다. 프롬프트 캐싱(컨텍스트 캐시·프리픽스 캐시라고도 함)은 이 겹치는 부분을 저장해 두어 한 번만 처리하면 되게 한다 — 캐시가 없으면 모델은 매 질의마다 시스템 프롬프트를 다시 처리해야 한다. 긴 문서(책·코드베이스)를 여러 질의가 공유하거나, 긴 대화의 이전 메시지 처리 결과를 재사용할 때도 유용하다. 시스템 프롬프트가 1,000토큰이고 애플리케이션이 하루 100만 건을 호출한다면, 프롬프트 캐시는 하루에 약 10억 개의 반복 입력 토큰 처리를 절약해 준다. 다만 공짜는 아니다 — KV 캐시처럼 프롬프트 캐시도 메모리 공간을 차지하고, 모델 API에 이 기능이 없다면 직접 구현하는 데 상당한 엔지니어링이 필요하다. Kim 등(2023, 2023년 11월)의 연구 이후 여러 모델 API에 빠르게 도입됐다 — 구글 제미나이는 캐시된 입력 토큰에 75% 할인을 제공하되 캐시 저장 자체에 별도 비용(집필 시점 시간당 100만 토큰당 1.00달러)을 매기고, 앤트로픽은 캐시된 컨텍스트가 길수록 절약폭이 커지는 최대 90% 비용 절감과 최대 75% 지연 시간 감소를 약속한다. 앤트로픽(2024)의 수치로는 "책과 대화하기"(10만 토큰 캐시)에서 TTFT가 11.5초→2.4초(-79%)·비용 -90%, "다수 예시를 통한 프롬프트 입력"(1만 토큰)에서 1.6초→1.1초(-31%)·비용 -86%, 긴 시스템 프롬프트를 포함한 10턴 멀티 턴 대화에서 약 10초→약 2.5초(-75%)·비용 -53%가 보고됐다.
5.4 병렬 처리 전략
가속기는 애초에 병렬 처리를 위해 만들어졌다. 가장 구현하기 간단한 전략은 복제 병렬 처리다 — 모델의 복제본을 여러 개 만들어 요청을 나눠 처리한다(학습에서는 이를 데이터 병렬 처리라 부른다). 복제본이 많을수록 더 많은 요청을 동시에 처리하지만 더 많은 칩이 필요하다 — 크기가 다른 모델들(8B·13B·34B·70B)과 메모리 용량이 다른 GPU들(24·40·48·80GB)을 어떻게 짝지을지는 빈 패킹 문제가 된다(예: 40GB GPU에 13B 모델 3개를 올릴지, 34B 모델 하나를 위해 남겨둘지).
모델이 너무 커서 한 머신에 들어가지 않을 때는 모델 병렬 처리로 여러 머신에 나눈다. 추론에서 가장 흔한 방법은 텐서 병렬 처리(연산자 내 병렬 처리)다 — 한 연산자(예: 행렬 곱셈)에 포함된 텐서를 여러 장치로 쪼개 병렬 실행한다. 단일 머신에 안 맞는 큰 모델을 서비스할 수 있게 해 주고 지연 시간도 줄이지만, 추가 통신 오버헤드가 그 이점을 깎아 먹을 수 있다. 파이프라인 병렬 처리는 모델 연산을 여러 독립적 단계로 나눠 각 단계를 다른 장치에 배정하고, 배치를 더 작은 마이크로 배치로 나눠 겹쳐 실행한다 — 여러 머신에서 큰 모델을 서비스할 수 있게 하지만 단계 간 통신 때문에 요청당 총 지연 시간이 늘어난다. 그래서 엄격한 지연 시간 요구가 있는 추론에서는 보통 파이프라인 병렬 처리 대신 복제 병렬 처리를 선호하고, 처리량이 중요한 학습에서는 파이프라인 병렬 처리가 흔히 쓰인다. 이 밖에 긴 입력 시퀀스를 더 효율적으로 다루기 위한 컨텍스트 병렬 처리(입력 시퀀스 자체를 여러 장치로 분할)와 시퀀스 병렬 처리(어텐션·피드포워드 같은 연산자들을 여러 장치로 분할)도 있다.
핵심 개념 정리
| 개념 | 한 줄 설명 |
|---|---|
| 연산 제약 vs 메모리 대역폭 제약 | 시간이 FLOP에 좌우되는가(연산 제약) vs 데이터 전송 속도에 좌우되는가(대역폭 제약) — 산술 강도·루프라인 차트로 구분 |
| 프리필·디코딩 | 자기회귀 LM 추론의 두 단계 — 프리필(입력 병렬 처리, 연산 제약) · 디코딩(출력 순차 생성, 대역폭 제약) |
| TTFT·TPOT | 첫 토큰까지의 시간(프리필 대응) · 토큰당 생성 시간(디코딩 대응). 둘의 합으로 전체 지연 시간을 계산 |
| 처리량·굿풋 | 처리량은 초당 생성 토큰 수(비용과 직결). 굿풋은 그중 SLO를 만족하는 것만 센 값 |
| MFU·MBU | 이론상 최대 FLOP/s·대역폭 대비 실제 활용 비율 — nvidia-smi의 GPU 활용률과 다른, 더 정확한 지표 |
| 가속기 핵심 사양 | 연산 성능(FLOP/s) · 메모리 크기·대역폭(DRAM<HBM<SRAM 순으로 빨라지고 작아짐) · 전력(TDP) |
| 모델 압축 3종 | 양자화(정밀도↓) · 증류(작은 모델이 큰 모델 모방) · 프루닝(기여 적은 파라미터 제거/영점화) |
| 추측 디코딩 | 약한 초안 모델이 여러 토큰을 만들고 목표 모델이 병렬 검증 — 디코딩을 프리필처럼 바꾸는 효과 |
| 참조 기반 추론 | 반복되는 입력 구간을 새로 생성하지 않고 그대로 복사 — 추가 모델 불필요, 중복 많은 작업에 유효 |
| 병렬 디코딩 | 순차적 의존성을 없애고 여러 미래 토큰을 동시 생성 후 검증(룩어헤드·메두사) |
| KV 캐시 | 이전 토큰의 키·값 벡터를 재사용하는 캐시. 크기는 시퀀스 길이·배치 크기에 선형 비례해 커짐 |
| 어텐션 재설계 3종 | 로컬 윈도우(윈도우 밖 생략) · 크로스 레이어(레이어 간 공유) · (그룹) 쿼리 어텐션(쿼리 헤드 간 공유) |
| 배치 처리 3종 | 정적(다 찰 때까지 대기) · 동적(크기/시간 조건) · 연속(끝난 자리에 바로 채움) |
| 프리필-디코딩 분리 | 연산 특성이 다른 두 단계를 다른 인스턴스에 배정해 자원 경쟁을 없앰 |
| 프롬프트 캐싱 | 프롬프트의 겹치는 부분(시스템 프롬프트 등)을 재사용 — 지연 시간·비용을 함께 줄임 |
| 병렬 처리 전략 | 복제(가장 단순) · 텐서(연산자 내부 분할) · 파이프라인(단계별 분할) · 컨텍스트·시퀀스(긴 입력용) |
실무 체크리스트
- [ ] 최적화를 시작하기 전에, 이 작업이 연산 제약인지 메모리 대역폭 제약인지 루프라인 차트나 산술 강도로 확인했는가?
- [ ] 지연 시간을 평균이 아니라 p50·p90·p99 백분위수로 보고 있는가(이상치에 왜곡되지 않는가)?
- [ ] 처리량·비용만 보지 않고, SLO를 만족하는 굿풋 기준으로도 서비스를 평가했는가?
- [ ] "GPU 활용률"이 nvidia-smi 지표인지 MFU/MBU인지 구분해서 보고했는가?
- [ ] 이 애플리케이션이 롱 컨텍스트·큰 배치를 다룬다면, KV 캐시 크기를 공식으로 직접 계산해 하드웨어 메모리로 감당 가능한지 확인했는가?
- [ ] 반복되는 시스템 프롬프트·긴 문서·멀티 턴 대화가 있다면 프롬프트 캐싱을 검토했는가?
- [ ] 지연 시간이 중요한 작업에 파이프라인 병렬 처리를 쓰고 있지는 않은가(복제 병렬 처리가 더 적합할 수 있다)?
- [ ] 모델 수준 최적화(양자화·프루닝·추측 디코딩 등)를 적용한 뒤 출력 품질이 그대로인지 벤치마크로 재확인했는가?
- [ ] 지연 시간·처리량·비용·모델 품질 네 가지 트레이드오프 중 이 애플리케이션에서 타협 불가능한 기준부터 먼저 정했는가?
연습문제
- 진단. 어떤 팀이 챗봇 서비스의 TTFT는 빠른데 TPOT가 느리다는 불만을 받았다. 이 장 §1.2·§2.1의 개념을 근거로, 프리필과 디코딩 중 어느 단계에 문제가 있을 가능성이 높은지, 그리고 §4·§5의 기법 중 무엇을 먼저 검토해야 하는지 설명하라.
- 계산. 라마 2-13B 계열 모델을 배치 크기 16, 시퀀스 길이 4,096, FP16으로 서빙하려 한다. §4.3의 공식으로 KV 캐시 메모리를 직접 계산하고, 배치 크기를 32로 두 배 늘리면 이 값이 어떻게 바뀌는지 설명하라.
- 선택. 검색 증강 코드 리뷰 챗봇을 만드는데, 응답의 상당 부분이 입력 코드를 거의 그대로 인용한다. §4.2의 세 가지 자기회귀 디코딩 가속 기법 중 어느 것이 가장 적합한지, 그리고 그 이유를 설명하라.
- 설계. 지연 시간에 민감한 온라인 챗봇과, 지연 시간에 관대한 야간 배치 요약 작업을 같은 GPU 클러스터로 서비스해야 한다. §5.1·§5.2·§5.4의 기법 중 무엇을 각각에 적용할지 근거를 들어 설계하라.
- 비교. 시스템 프롬프트가 짧고 매 요청이 서로 무관한 검색 API와, 시스템 프롬프트가 길고 같은 문서에 대해 반복 질의가 들어오는 문서 챗봇이 있다. §5.3의 프롬프트 캐싱이 두 서비스에 주는 이득이 왜 다른지 설명하라.
최신 동향 (2026-09 기준)
최신 동향 (검증 2026-09-12) — 이 장이 설명하는 지표·원리(TTFT/TPOT·MFU/MBU·KV 캐시 공식·배치 처리 세 방식)는 책 내용 그대로 유효하다. 아래는 이 장 이후 하드웨어·서빙 관행이 바뀐 항목만 다룬다.
- 가속기 세대가 바뀌면서 이 장의 MBU 계산 전제(대역폭)가 크게 달라졌다. 이 장 §3.2·§4.3이 예로 든 엔비디아 H100(HBM3, 대역폭 3.35TB/s, FP8 밀집 3,958 TFLOPS)에 이어, 후속 세대인 블랙웰 B200은 HBM3e 180~192GB에 대역폭 약 7.7~8TB/s(H100 대비 약 2.3배)와 FP8 밀집 약 4,500 TFLOPS(FP4까지 지원하는 2세대 트랜스포머 엔진)를 낸다 — NVIDIA HGX B200 공식 기술 블로그. §2.3의 MBU 계산식(파라미터 수 × 파라미터당 바이트 × tokens/s ÷ 이론적 대역폭)은 그대로 유효하지만, 분모(이론적 대역폭)가 세대마다 크게 뛰므로 같은 처리량이라도 최신 가속기에서는 MBU 수치 자체가 낮게 나올 수 있다는 점에 유의해야 한다.
- §5.2의 프리필-디코딩 분리가 연구 단계에서 주요 서빙 프레임워크의 기본 기능으로 자리 잡았다. 이 장이 소개한 DistServe(2024)류의 연구 이후, vLLM은 v0.8 이상(V1 엔진)에서 NixlConnector로 프리필-디코딩 분리를 네이티브로 지원하고 SGLang도 라우터 API로 분리 서빙을 지원한다 — vLLM 공식 분리 프리필 문서. 메타는 vLLM 팀과 협업해 이 분리 구조를 내부 프로덕션 트래픽에 적용했다고 공식 밝혔다 — PyTorch 공식 블로그. 다만 이 장 §5.2가 짚은 트레이드오프(프리필→디코딩 인스턴스 간 통신 오버헤드, ITL/TTFT 목표에 따른 인스턴스 비율 조정)의 판단 기준 자체는 바뀌지 않았다.
부록 A. 핵심 비교표
연산 제약 vs 메모리 대역폭 제약
| 구분 | 연산 제약 | 메모리 대역폭 제약 |
|---|---|---|
| 결정 요인 | 연산량(FLOP) | 메모리↔프로세서 전송 속도 |
| 완화 방법 | 칩을 더 분산 / FLOP/s가 높은 칩 | 대역폭이 넓은 칩 |
| 자기회귀 LM 단계 | 프리필 | 디코딩 |
| 전형적 예 | 암호 해독, 이미지 생성 추론 | 자기회귀 LM 디코딩 |
MFU vs MBU
| 구분 | MFU | MBU |
|---|---|---|
| 재는 대상 | 이론상 최대 FLOP/s 대비 실제 처리량 | 이론상 최대 대역폭 대비 실제 사용 대역폭 |
| 연산 제약 작업에서 | 보통 높다 | 보통 낮다 |
| 대역폭 제약 작업에서 | 보통 낮다 | 보통 높다 |
| nvidia-smi "GPU 활용률"과 관계 | 다른 지표 — 작업 처리 시간 비율이 아니라 알찬 정도 | 동일 성격, 대역폭 축으로 |
추측 디코딩 vs 참조 기반 추론 vs 병렬 디코딩
| 구분 | 추측 디코딩 | 참조 기반 추론 | 병렬 디코딩 |
|---|---|---|---|
| 후보 토큰 출처 | 별도 초안 모델 | 입력(컨텍스트) | 원본 모델의 추가 헤드 또는 같은 디코더 |
| 추가 모델 필요 | 필요(초안 모델) | 불필요 | 헤드만 추가(메두사) 또는 불필요(룩어헤드) |
| 가장 잘 맞는 상황 | 범용 | 컨텍스트-출력 중복 큰 작업(코딩·문서 인용) | 예측 가능한 다음 토큰이 많은 작업 |
정적 vs 동적 vs 연속 배치 처리
| 구분 | 정적 | 동적 | 연속 |
|---|---|---|---|
| 처리 시점 | 정원이 다 찰 때 | 정원 또는 최대 대기 시간 중 먼저 | 응답이 끝나는 대로 즉시 |
| 짧은 응답의 대기 | 긴 요청까지 대기 | 조건 충족 시까지 대기 | 대기 없음(즉시 반환) |
| 연산 낭비 | 큼(다 찰 때까지 유휴) | 있음(덜 찬 배치 처리 가능) | 작음 |
텐서 병렬 처리 vs 파이프라인 병렬 처리
| 구분 | 텐서 병렬 처리 | 파이프라인 병렬 처리 |
|---|---|---|
| 분할 단위 | 한 연산자 내부의 텐서 | 모델의 연산 단계(레이어 묶음) |
| 지연 시간 | 통신 오버헤드는 있지만 줄이는 효과 | 단계 간 통신으로 총 지연 시간 증가 |
| 선호되는 상황 | 추론(지연 시간 중요) | 학습(처리량 중요) |
부록 B. 추천 참고 자료
외부 자료 (Tier 1 공식·원논문, 생존 확인 2026-09-12)
- Roofline 모델 원논문 — §1.1의 연산 제약·메모리 대역폭 제약 구분의 원 출처. Roofline: An Insightful Visual Performance Model for Multicore Architectures (Williams, Waterman, Patterson, 2009)
- PaLM 논문 — §2.3의 MFU 개념과 표 9-1 수치의 출처. PaLM: Scaling Language Modeling with Pathways (Chowdhery et al., 2022)
- 추측 디코딩 원논문 — §4.2의 초안·목표 모델 검증 절차 출처. Fast Inference from Transformers via Speculative Decoding (Leviathan, Kalman, Matias, 2023)
- 플래시 어텐션 원논문·공식 저장소 — §4.3의 어텐션 커널 융합 설명 출처. FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness (Dao et al., 2022) · 공식 저장소
- vLLM(페이지드 어텐션) 원논문 — §4.3의 KV 캐시 관리 최적화 출처. Efficient Memory Management for Large Language Model Serving with PagedAttention (Kwon et al., 2023)
- DistServe 원논문 — §5.2의 프리필-디코딩 분리 연구 출처. DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving (Zhong et al., 2024)
- vLLM 공식 문서 — 최신 동향이 다룬 프리필-디코딩 분리의 실제 구현. Disaggregated Prefilling — vLLM 공식 문서
더 해보기 — 읽고 끝내지 않으려면
- §4.3의 KV 캐시 공식에 자신이 서빙하려는 모델의 레이어 수·모델 차원·목표 배치 크기·컨텍스트 길이를 넣어 필요한 메모리를 직접 계산해 본다(그리고 원문의 인쇄 오류처럼 손으로 검산하는 습관을 들여 본다).
- §2.3의 MBU 계산식에 자신이 쓰는 모델의 파라미터 수·정밀도·실측 tokens/s를 넣고, 사용 중인 GPU의 공식 대역폭 사양과 비교해 실제 MBU를 가늠해 본다.
본 책 연계 챕터
| 챕터 | 이 장이 다루지 않은 것 |
|---|---|
| 2장 §2.1 모델 아키텍처 | 이 장이 선행 지식으로 전제한 트랜스포머·어텐션·프리필/디코드 개념 자체의 상세 |
| 7장 §4.2 수치 표현 방식과 양자화 | 이 장 §4.1이 "이미 다뤘다"고 넘어간 양자화의 수치 정밀도별 계산법 |
| 8장 §6 모델 증류 | 이 장 §4.1이 "이미 다뤘다"고 넘어간 교사-학생 모델 증류의 구체적 절차와 사례 |
| 10장 §4단계 — 캐시로 지연 시간 줄이기 | 이 장 §5.3의 프롬프트 캐싱을 시스템 아키텍처 전체 관점(캐시 계층을 어디에 둘지)에서 다시 다루는 부분 |
부록 C. 연습문제 풀이
-
(TTFT 정상·TPOT 저하 진단) TTFT는 프리필 단계의 성능을 반영하고 TPOT는 디코딩 단계의 성능을 반영한다(§2.1). TTFT가 빠른데 TPOT가 느리다면 문제는 디코딩 단계 — 즉 메모리 대역폭 병목(§1.2)일 가능성이 높다. 먼저 §5.1의 배치 처리 방식(짧은 응답이 긴 응답 때문에 지연되고 있지 않은지 — 연속 배치 처리를 쓰고 있는지)과 §5.2의 프리필-디코딩 분리(디코딩 인스턴스가 프리필 작업과 자원을 경쟁하고 있지 않은지)를 먼저 점검하고, 모델 자체를 손볼 여지가 있다면 §4.3의 KV 캐시 최적화(그룹 쿼리 어텐션 등으로 디코딩마다 불러오는 캐시 크기를 줄이는 것)를 검토한다.
-
(KV 캐시 계산) §4.3의 공식
2 × B × S × L × H × M에 라마 2-13B의 값(L=40, H=5,120, FP16이므로 M=2바이트)과 문제의 조건(B=16, S=4,096)을 대입하면2 × 16 × 4,096 × 40 × 5,120 × 2 = 53,687,091,200바이트 ≈ 53.7GB다(본문 예시의 B=32·S=2,048 조합과 정확히 같은 값이 나오는데, 배치를 절반으로 줄이고 시퀀스 길이를 두 배로 늘린 것이 서로 상쇄되기 때문이다 — 공식이 B와 S 모두에 선형이라는 것을 보여주는 좋은 예다). 배치 크기를 32로 두 배 늘리면 공식이 B에 선형이므로 캐시 크기도 정확히 두 배인 약 107.4GB가 된다. -
(자기회귀 디코딩 가속 기법 선택) 코드 리뷰 챗봇의 응답이 입력 코드를 거의 그대로 인용한다는 것은 컨텍스트(입력)와 출력 사이에 상당한 중복이 있다는 뜻이다. §4.2가 설명했듯 이런 상황은 참조 기반 추론에 정확히 들어맞는 사례다 — 반복되는 구간을 모델이 새로 생성하지 않고 입력에서 그대로 복사해 속도를 높이고, 추측 디코딩처럼 별도 초안 모델을 학습·유지할 필요도 없다.
-
(온라인 vs 배치 워크로드 분리 설계) 지연 시간에 민감한 온라인 챗봇에는 §5.1의 동적 또는 연속 배치 처리(짧은 대기·빠른 반환)와 §5.4의 복제 병렬 처리(파이프라인 병렬 처리보다 지연 시간에 유리)를 적용한다. 지연 시간에 관대한 야간 배치 요약 작업에는 §1.4의 배치 API 개념대로 정적 배치 처리로 처리량을 극대화하고, 모델이 한 머신에 안 들어갈 정도로 크다면 처리량이 중요한 이 워크로드에는 §5.4의 파이프라인 병렬 처리도 고려할 수 있다. 같은 클러스터를 쓴다면 §5.2의 프리필-디코딩 분리 개념을 확장해, 온라인 요청과 배치 요청을 아예 다른 인스턴스 풀로 분리해 서로의 SLO(굿풋)를 침범하지 않게 하는 것이 핵심이다.
-
(프롬프트 캐싱 이득의 차이) §5.3에 따르면 프롬프트 캐싱은 여러 요청에 걸쳐 겹치는 부분을 재사용하는 기법이다. 시스템 프롬프트가 짧고 매 요청이 서로 무관한 검색 API는 애초에 재사용할 겹치는 부분이 적어 캐싱의 이득이 작다. 반면 시스템 프롬프트가 길고 같은 문서에 반복 질의가 들어오는 문서 챗봇은 문서 전체(또는 긴 시스템 프롬프트)를 한 번만 처리하고 이후 질의마다 재사용할 수 있어, 본문이 인용한 앤트로픽의 "책과 대화하기" 사례(TTFT -79%, 비용 -90%)처럼 캐싱의 이득이 훨씬 크다 — 캐싱 이득은 결국 "겹치는 부분의 크기 × 재사용 빈도"에 비례한다.
클릭하거나 Space를 눌러 뒤집기